package com.examination.client.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.examination.client.config.ChuangMessageProperties;
import com.examination.client.config.MessageProperties;
import com.examination.client.config.SpringConfig;
import com.examination.client.domian.dto.*;
import com.examination.client.domian.vo.MessageCountVO;
import com.examination.client.entity.BuyMessageRecord;
import com.examination.client.entity.CourierInfo;
import com.examination.client.entity.CourierSite;
import com.examination.client.entity.SiteMessage;
import com.examination.client.exception.BusinessException;
import com.examination.client.redis.RedisCache;
import com.examination.client.service.*;
import com.examination.client.util.JsonUtils;
import com.examination.client.util.ThreadLocalUtils;
import com.examination.client.util.UserInfoUtil;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.util.TextUtils;
import org.aspectj.bridge.IMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Slf4j
@Service
public class MessageServiceImpl implements MessageService {
    @Resource
    private ICourierInfoService courierInfoService;

    @Resource
    ICourierSiteService courierSiteService;
    @Resource
    ISiteMessageService siteMessageService;
    @Resource
    private MessageProperties messageProperties;

    @Resource
    private ChuangMessageProperties chuangMessageProperties;

    @Resource
    OrderService orderService;

    @Autowired
    @Qualifier(SpringConfig.ASYNC_EXECUTOR)
    Executor asyncExecutor;

    @Autowired
    private RedisCache redisCache;


    @Override
    public Boolean send(SendMessageDTO sendMessageDTO) {
        Integer availableNum = availableNum();
        if (sendMessageDTO.getIdList().size() > availableNum) {
            throw new RuntimeException("可用短信数量不足,请充值后再发送");
        }
        //查询快递信息列表
        LambdaQueryWrapper<CourierInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(CourierInfo::getId,sendMessageDTO.getIdList());
        List<CourierInfo> courierInfoList = courierInfoService.list(queryWrapper);
        if(CollectionUtil.isNotEmpty(courierInfoList)){
            List<CourierMessageDTO> courierMessageDTOList = Lists.newArrayList();
            List<CourierSite> courierSiteList = courierSiteService.list();
            Map<Integer, CourierSite> siteMap = courierSiteList.stream().collect(Collectors.toMap(CourierSite::getId, account -> account));
            courierInfoList.forEach(e->{
                CourierSite courierSite = siteMap.get(e.getSiteId());
                if(Objects.isNull(courierSite)){
                    throw new RuntimeException("快递单号："+e.getCourierCode()+"对应站点不存在");
                }
                CourierMessageDTO courierMessageDTO = new CourierMessageDTO();
                courierMessageDTO.setId(e.getId());
                TemplateParamDTO templateParamDTO = new TemplateParamDTO();
                templateParamDTO.setAddress(courierSite.getSiteAddress());
                templateParamDTO.setCourierCode(e.getCourierCode());
                templateParamDTO.setCourierCompanyName(e.getCourierName());
                templateParamDTO.setMarketName(courierSite.getSiteName());
                templateParamDTO.setPhone(Long.valueOf(courierSite.getPhone()));
                courierMessageDTO.setTemplateParamDTO(templateParamDTO);
                courierMessageDTO.setUserPhone(e.getUserPhone());
                courierMessageDTOList.add(courierMessageDTO);
            });
            Integer siteId = UserInfoUtil.getSiteId();
            if(Objects.isNull(siteId)){
                throw new RuntimeException("获取站点id失败");
            }
            CompletableFuture.runAsync(() -> {
                sndMessage(courierMessageDTOList,siteId);
            }, asyncExecutor);
        }

        return true;
    }

    @Override
    public Integer availableNum() {
        LambdaQueryWrapper<SiteMessage> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SiteMessage::getSiteId, UserInfoUtil.getSiteId());
        SiteMessage siteMessage = siteMessageService.getOne(queryWrapper);
        return Objects.isNull(siteMessage) ? 0:siteMessage.getMessageNum();
    }

    @Override
    public Boolean scanSend(ScanSendMessageDTO scanSendMessageDTO) {
        Integer availableNum = availableNum();
        if (availableNum<=0) {
            throw new RuntimeException("可用短信数量不足,请充值后再发送");
        }

        LambdaQueryWrapper<CourierInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourierInfo::getCourierCode,scanSendMessageDTO.getCourierCode());
        queryWrapper.eq(CourierInfo::getSiteId,UserInfoUtil.getSiteId());
        CourierInfo courierInfo = courierInfoService.getOne(queryWrapper);
        if(Objects.isNull(courierInfo)){
            throw new RuntimeException("该快递不存在");
        }
        if(1==courierInfo.getAdviceStatus()){
            throw new RuntimeException("请勿重复发送");
        }
        CourierSite courierSite = courierSiteService.getById(courierInfo.getSiteId());
        if(Objects.isNull(courierSite)){
            throw new RuntimeException("该快递对应的站点不存在");
        }

        List<CourierMessageDTO> courierMessageDTOList = Lists.newArrayList();

        TemplateParamDTO templateParamDTO = new TemplateParamDTO();
        templateParamDTO.setCourierCompanyName(courierInfo.getCourierName());
        templateParamDTO.setCourierCode(courierInfo.getCourierCode());
        templateParamDTO.setMarketName(courierSite.getSiteName());
        templateParamDTO.setPhone(Long.valueOf(courierSite.getPhone()));
        templateParamDTO.setAddress(courierSite.getSiteAddress());
        CourierMessageDTO courierMessageDTO = new CourierMessageDTO();
        courierMessageDTO.setTemplateParamDTO(templateParamDTO);
        courierMessageDTO.setUserPhone(courierInfo.getUserPhone());
        courierMessageDTOList.add(courierMessageDTO);

        //发送短信
        sndMessage(courierMessageDTOList,UserInfoUtil.getSiteId());

        return true;
    }

    @Override
    public String sendCode(String phone){
        String message = "";
        if (sndMessageNew(phone)){
            message = "验证码发送成功！";
        }else{
            message = "验证码发送失败！";
        }
        return message;
    }

    @Override
    public MessageCountVO count() {
        MessageCountVO messageCountVO = new MessageCountVO();
        LambdaQueryWrapper<SiteMessage> qeryWrapper = new LambdaQueryWrapper<>();
        qeryWrapper.eq(SiteMessage::getSiteId,"0");
        SiteMessage one = siteMessageService.getOne(qeryWrapper);
        messageCountVO.setMessageNum(one.getMessageNum());

        //查询最近一次购买条数
        LambdaQueryWrapper<BuyMessageRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BuyMessageRecord::getSiteId,"0");
        BuyMessageRecord buyMessageRecord = orderService.getOne(wrapper);
        messageCountVO.setBuyNum(buyMessageRecord.getMessageNum());
        return messageCountVO;
    }

    @Override
    public Boolean save(SiteMessageDTO siteMessageDTO) {
        LambdaQueryWrapper<SiteMessage> qeryWrapper = new LambdaQueryWrapper<>();
        qeryWrapper.eq(SiteMessage::getSiteId,"0");
        SiteMessage one = siteMessageService.getOne(qeryWrapper);
        one.setTotalBuyNum(one.getTotalBuyNum()+siteMessageDTO.getNum());
        one.setMessageNum(one.getMessageNum()+siteMessageDTO.getNum());
        one.setUpdateTime(new Date());
        siteMessageService.updateById(one);

        //修改记录
        LambdaUpdateWrapper<BuyMessageRecord> updateWrapper = new LambdaUpdateWrapper();
        updateWrapper.eq(BuyMessageRecord::getSiteId,"0");
        updateWrapper.set(BuyMessageRecord::getMessageNum,siteMessageDTO.getNum());
        updateWrapper.set(BuyMessageRecord::getUpdateTime,new Date());
        orderService.update(updateWrapper);
        return true;
    }


    /**
     * 批量发送他
     * @param courierMessageDTOList
     */
    public void sndMessage(List<CourierMessageDTO> courierMessageDTOList,Integer siteId) {
        Integer count=0;
        for (CourierMessageDTO e:courierMessageDTOList) {
            Boolean success = sndMessageNew(e);
            if(success){
                count++;
            }
            CourierInfo courierInfo = new CourierInfo();
            courierInfo.setId(e.getId());
            courierInfo.setAdviceStatus(1);
            courierInfoService.updateById(courierInfo);
        }
        LambdaQueryWrapper<SiteMessage> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SiteMessage::getSiteId,siteId);
        SiteMessage siteMessage = siteMessageService.getOne(queryWrapper);
        if(Objects.nonNull(siteMessage)){
            siteMessage.setAlreadyUseNum(siteMessage.getAlreadyUseNum()+count);
            siteMessage.setMessageNum(siteMessage.getTotalBuyNum()-siteMessage.getAlreadyUseNum());
            siteMessageService.updateById(siteMessage);
        }
    }

    /**
     * 发送短信
     * @param courierMessageDTO
     */
    public Boolean sndMessage(CourierMessageDTO courierMessageDTO) {
        DefaultProfile profile = DefaultProfile.getProfile("default", messageProperties.getAccessKeyId(), messageProperties.getAccessSecret());
        IAcsClient client = new DefaultAcsClient(profile);

        CommonRequest request = new CommonRequest();
        request.setMethod(MethodType.GET);
        request.setDomain(messageProperties.getDomain());
        request.setVersion("2017-05-25");
        request.setAction("SendSms");
        request.putQueryParameter("RegionId", "default");
        request.putQueryParameter("PhoneNumbers",courierMessageDTO.getUserPhone());
        request.putQueryParameter("SignName", messageProperties.getSignName());
        request.putQueryParameter("TemplateCode", messageProperties.getTemplateCode());
        request.putQueryParameter("TemplateParam", JsonUtils.toJson(courierMessageDTO.getTemplateParamDTO()));
        try {
            CommonResponse response = client.getCommonResponse(request);
            log.info("阿里云返回信息:{}",JsonUtils.toJson(response));
            JSONObject jsonObject = JSON.parseObject(response.getData());
            String code = jsonObject.get("Code").toString();
            if("OK".equals(code)){
                log.info("发送成功");
                return true;
            }
            return false;
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return false;
    }

    public Boolean sndMessageNew(CourierMessageDTO courierMessageDTO) {
        try {
            String getTokenData = getToken();
            System.out.println("getTokenData::" + getTokenData);
            JSONObject tokenJson = JSON.parseObject(getTokenData);
            int status = tokenJson.getIntValue("status");
            String info = tokenJson.getString("info");
            String access_token = "";
            if(status == 1){
                JSONObject data = tokenJson.getJSONObject("data");
                access_token = data.getString("access_token");
                int expires_in = data.getIntValue("expires_in");//access_token的生命周期，单位是秒数。过期之后要重新获取
            }

            String app_key = chuangMessageProperties.getAppKey();
            String sendSmsResult = sendSms(app_key,access_token,courierMessageDTO);
            System.out.println("sendSmsResult::" + sendSmsResult );
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public Boolean sndMessageNew(String phone){
        try {
            String getTokenData = getToken();
            System.out.println("getTokenData::" + getTokenData);
            JSONObject tokenJson = JSON.parseObject(getTokenData);
            int status = tokenJson.getIntValue("status");
            String info = tokenJson.getString("info");
            String access_token = "";
            if(status == 1){
                JSONObject data = tokenJson.getJSONObject("data");
                access_token = data.getString("access_token");
                int expires_in = data.getIntValue("expires_in");//access_token的生命周期，单位是秒数。过期之后要重新获取
            }
            String app_key = chuangMessageProperties.getAppKey();
            String sendSmsResult = sendSms(app_key,access_token,phone);
            System.out.println("sendSmsResult::" + sendSmsResult );
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    private String getToken() {
        try {
            URL url = new URL("https://api.chuangcache.com/OAuth/authorize");
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setDoInput(true);
            conn.setDoOutput(true);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type","application/json");

            DataOutputStream out = new DataOutputStream(conn.getOutputStream());
            JSONObject obj = new JSONObject();
            obj.put("appid", chuangMessageProperties.getAk());//填写appkey (客服人员会给出)
            obj.put("appsecret", chuangMessageProperties.getSk());//填写appsecret(客服人员会给出)
            obj.put("grant_type", chuangMessageProperties.getGrantType());
            out.writeBytes(obj.toString());
            out.flush();
            out.close();

            InputStream inStream = conn.getInputStream();
            return new String(readInputStream(inStream), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private String sendSms(String app_key,String access_token,CourierMessageDTO courierMessageDTO) {
        OutputStreamWriter out = null;
        try {
            URL url = new URL("http://sms.chuangcache.com/api/sms/ordinary");
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setDoInput(true);
            conn.setDoOutput(true);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type","application/json");

            JSONObject obj = new JSONObject();
            obj.put("access_token", access_token);
            obj.put("app_key", app_key);
            obj.put("mobile", courierMessageDTO.getUserPhone());//手机号码
            TemplateParamDTO templateParamDTO = courierMessageDTO.getTemplateParamDTO();
            String courierCompanyName = templateParamDTO.getCourierCompanyName();
            if (TextUtils.isEmpty(courierCompanyName)) {
                courierCompanyName = "";
            }
            String content = String.format(chuangMessageProperties.getContent(),
                    courierCompanyName, templateParamDTO.getCourierCode(),
                    templateParamDTO.getMarketName(), templateParamDTO.getAddress(), templateParamDTO.getPhone());
            obj.put("content", content);//发送内容
            obj.put("time", System.currentTimeMillis() + "");

            out = new OutputStreamWriter(
                    conn.getOutputStream());
            out.write(obj.toString());
            out.flush();

            InputStream inStream = conn.getInputStream();
            return new String(readInputStream(inStream), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private String sendSms(String app_key,String access_token,String phone){
        OutputStreamWriter out = null;
        try {
            URL url = new URL("http://sms.chuangcache.com/api/sms/ordinary");
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setDoInput(true);
            conn.setDoOutput(true);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type","application/json");

            JSONObject obj = new JSONObject();
            obj.put("access_token", access_token);
            obj.put("app_key", app_key);
            obj.put("mobile", phone);//手机号码
            Random rand = new Random();
            String randomNumber = String.format("%06d", rand.nextInt(900000) + 100000); // 生成一个六位数的随机数
            obj.put("content", randomNumber);//发送内容
            obj.put("time", System.currentTimeMillis() + "");

            out = new OutputStreamWriter(
                    conn.getOutputStream());
            out.write(obj.toString());
            out.flush();

            InputStream inStream = conn.getInputStream();
            ThreadLocalUtils.set(phone,randomNumber);
            redisCache.setCacheObject(phone,randomNumber);
            redisCache.expire(phone, 1, TimeUnit.MINUTES);
            return new String(readInputStream(inStream), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public byte[] readInputStream(InputStream inStream) throws Exception {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outStream.write(buffer, 0, len);
        }
        byte[] data = outStream.toByteArray();
        outStream.close();
        inStream.close();
        return data;
    }

}
